#pragma once

#include "iostream"
#include "vector"
#include "algorithm"

using namespace std;
/*HJJ QQ479287006
 *假设你正在爬楼梯。需要 n 阶你才能到达楼顶。

每次你可以爬 1 或 2 个台阶。你有多少种不同的方法可以爬到楼顶呢？

 

示例 1：

输入：n = 2
输出：2
解释：有两种方法可以爬到楼顶。
1. 1 阶 + 1 阶
2. 2 阶
示例 2：

输入：n = 3
输出：3
解释：有三种方法可以爬到楼顶。
1. 1 阶 + 1 阶 + 1 阶
2. 1 阶 + 2 阶
3. 2 阶 + 1 阶

来源：力扣（LeetCode）
链接：https://leetcode.cn/problems/climbing-stairs
著作权归领扣网络所有。商业转载请联系官方授权，非商业转载请注明出处。
 * */
//递归超出时间限制了
int climbStairs1(int n) {
    if (n == 1)
        return 1;
    if (n == 2)
        return 2;
    return climbStairs1(n - 1) + climbStairs1(n - 2);
}

int climbStairs(int n) {
    if (n == 1)
        return 1;
    if (n == 2)
        return 2;

    int now = 2;
    int last = 1;

    int index = 3;
    int sum = 0;
    while (index != n) {
        sum = last + now;
        last = now;
        now = sum;
        index++;

    }

    //什么呀为什么会溢出
    return sum;
}


//第二种dp //完全背包问题
// 每次有 1 2 两种物品  求 装满n的背包有几种方法
//因此这个可以拓展到 多种走发了 不止能上一步或者两部 三部都行
//TODO 如果我来⾯试的话，我就会先给候选⼈出⼀个 本题原题，看其表现，如果顺利写出来，进⽽在要求每次 可以爬[1 - m]个台阶应该怎么写
int climbStairs33(int n) {
    int arr[] = {1, 2};

    //我震惊了 这个为什么是排列问题
    //TODO 例如 3  1 1 1    1 2    21 排列问题先遍历背包后遍历物品
    vector<int> dp(n + 1, 0);
    dp[0] = 1;
    for (int j = 0; j < n + 1; ++j) {

        for (int i = 0; i < 2; ++i) {
            if (j - arr[i] >= 0)
                dp[j] += dp[j - arr[i]];
        }

    }


    return dp[n];
}


///如果一次可以上m个台阶
//每次可以上多个台阶问题
void testMore(int n, int m) {

    vector<int> dp(n + 1, 0);
    //代表是 第n个台阶的可以组成的方式
    dp[0] = 1;

    //先 背包是排列    后背包是组合   此问题是排列问题
    //3 3   1 1 1 . 1 2    2 1.  3
    //4 3   1 1 1 1  1 2 1  1 1 2  2 1 1  1 3  3 1  2 2
    for (int i = 1; i <= n; ++i) {

        for (int j = 0; j <= m; ++j) {

            if (i >= j)
                dp[i] = dp[i] + dp[i - j];
        }

    }

    cout << dp[n];

}